package win.larryzeal.c01;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.Authenticator;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.DefaultSubjectFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.SubjectContext;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.junit.Test;
import win.larryzeal.c01.realm.RealmA;

/**
 * ini代表的是一种realm，里面存储了账号密码，也可以有角色权限等信息，还可以进行其他设置！
 * <p>
 * Shiro 不提供维护用户/权限，而是通过 Realm 让开发人员自己注入！
 * <p>
 * 注意，Authenticator，其核心就一个方法，获取认证信息。
 * 而Authorizer，则有多个方法，isPermitted/hasPermission|hasRole/checkRole等。不像Authenticator有统一入口。
 * <p>
 * Created by 张少昆 on 2017/11/18.
 */
public class C01_basic {

    //注意，在这里没有任何地方注册了RealmA，但是也能用！只能是根据ini创建了一个realm！
    //org.apache.shiro.config.IniSecurityManagerFactory.shouldImplicitlyCreateRealm()  是这个方法
    //被这个调用 org.apache.shiro.config.IniSecurityManagerFactory.createDefaults()
    @Test
    public void iniRealm_01(){
        IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:c01/c01.ini");//TODO 不能是classpath:/c01/c01.ini
        SecurityManager securityManager = iniSecurityManagerFactory.createInstance();//RealmSecurityManager!!!
        SecurityUtils.setSecurityManager(securityManager);


        // securityManager.authenticate();//
        // securityManager.getAuthenticator();//事实上已经有了认证器，而且是多模的，org.apache.shiro.mgt.AuthenticatingSecurityManager.AuthenticatingSecurityManager


        Subject subject = SecurityUtils.getSubject();//如果设置了就有，否则就创建一个。见这个方法即可。
        AuthenticationToken token = new UsernamePasswordToken("zhang", "123");

        subject.login(token);
        System.out.println(subject.isAuthenticated());
    }

    // 示意原理，而非直接使用SecurityUtils
    @Test
    public void realmA(){
        //1、创建realm
        RealmA realmA = new RealmA();
        //2、创建SecurityManager - 加入realm
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(realmA);
        //3、创建subject
        SubjectContext ctx = new DefaultSubjectContext();
        ctx.setSecurityManager(defaultSecurityManager);//必须有
        Subject subject = new DefaultSubjectFactory().createSubject(ctx); // 还要自己创建并指定ctx！SecurityUtils可以直接创建 - 如果没有的话。
        //4、创建登录用的token
        AuthenticationToken token = new UsernamePasswordToken("zhang", "123");
        //5、登录
        Subject login = defaultSecurityManager.login(subject, token);
        //6、校验
        System.out.println(subject.isAuthenticated()); //TODO 登陆后不会处理原有的subject！
        System.out.println(login == subject);//TODO 而原有的subject和登录返回的subject不是同一个！
        System.out.println(login.isAuthenticated());//TODO 登录返回的subject才带有相应信息！！！
    }

    @Test
    public void r1(){
        System.out.println(SecurityUtils.getSubject());//没有提前设置sm，会报错
    }
}
